import pygame
import random
import os
import sys


# 定义常量
GRID_NUM = (10, 20)
MULTI = 300
GAME_AREA_SIZE = (MULTI, MULTI * 2)
WINDOW_SIZE = (GAME_AREA_SIZE[0] * 1.7, GAME_AREA_SIZE[1])
GRID_SIZE = (GAME_AREA_SIZE[0] / GRID_NUM[0], GAME_AREA_SIZE[1] / GRID_NUM[1])
FPS = 60


def resource_path(relative_path):
    """ 获取资源的正确路径，适用于开发环境和 PyInstaller 打包 """
    try:
        # PyInstaller 创建的临时文件夹路径
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


def check_collision(current_block, block_pos, grid):
    """碰撞检测"""
    for row in range(len(current_block)):
        for col in range(len(current_block[row])):
            if block_pos[1] + row - 1 >= GRID_NUM[1] or block_pos[0] + col - 1 >= GRID_NUM[0]:
                return True
            elif current_block[row][col] == 1 and grid[row + block_pos[1] - 1][col + block_pos[0] - 1] != 0:
                return True
    return False


def update(current_block, pos, color, interval, timer, grid, drop_timer, score):
    """更新游戏状态"""
    current_time = pygame.time.get_ticks()
    if current_time - timer > interval:
        new_pos = [pos[0], pos[1] + 1]
        if check_collision(current_block, new_pos, grid):
            base_row = pos[1]
            base_col = pos[0]
            for row in range(len(current_block)):
                for col in range(len(current_block[row])):
                    if current_block[row][col] == 1:
                        grid_row = row + base_row - 1
                        grid_col = col + base_col - 1
                        if 0 <= grid_row < len(grid) and 0 <= grid_col < len(grid[0]):
                            grid[grid_row][grid_col] = color
            # 清除行
            rows_cleared = clear_full_rows(grid)
            # 获取分数
            score = update_score(score, rows_cleared)
            current_block = []
            new_pos = pos
        drop_timer = current_time
        pos = new_pos

    return current_block, pos, drop_timer, score


def draw(screen, grid, current_block, current_color, block_pos, next_block, next_color, score):
    """渲染游戏内容"""
    # 绘制网格
    pygame.draw.rect(screen, (255, 255, 255), (0, 0, WINDOW_SIZE[0], WINDOW_SIZE[1]), 1)
    pygame.draw.rect(screen, (255, 255, 255), (0, 0, GAME_AREA_SIZE[0], GAME_AREA_SIZE[1]), 1)
    for _ in range(GRID_NUM[0]):
        pygame.draw.line(screen, (255, 255, 255), (GRID_SIZE[0] * _, 0),
                         (GRID_SIZE[0] * _, WINDOW_SIZE[1]))
    for _ in range(GRID_NUM[1]):
        if _ == 5:
            pygame.draw.line(screen, (255, 0, 0), (0, GRID_SIZE[1] * _),
                             (GAME_AREA_SIZE[0], GRID_SIZE[1] * _), 2)
        else:
            pygame.draw.line(screen, (255, 255, 255), (0, GRID_SIZE[1] * _),
                             (GAME_AREA_SIZE[0], GRID_SIZE[1] * _))

    # 绘制已落下的方块
    for i in range(len(grid)):
        for j in range(len(grid[i])):
            if grid[i][j] != 0:
                pygame.draw.rect(screen, grid[i][j],
                                 (GRID_SIZE[0] * j + 1, GRID_SIZE[1] * i + 1,
                                  GRID_SIZE[0] - 1, GRID_SIZE[1] - 1))
    # 绘制方块
    for row in range(len(current_block)):
        for col in range(len(current_block[row])):
            if current_block[row][col] == 1:
                pygame.draw.rect(screen, current_color,
                                 (GRID_SIZE[0] * (block_pos[0] - 1 + col) + 1,
                                  GRID_SIZE[1] * (block_pos[1] - 1 + row) + 1,
                                  GRID_SIZE[0] - 1, GRID_SIZE[1] - 1))
    # 绘制下一个方块
    for row in range(len(next_block)):
        for col in range(len(next_block[row])):
            if next_block[row][col] != 0:
                pygame.draw.rect(screen, next_color,
                                 (GRID_SIZE[0] * (col + 2) + 1 + GAME_AREA_SIZE[0],
                                  GRID_SIZE[1] * (row + 1) + 1 + WINDOW_SIZE[1] * 0.3,
                                  GRID_SIZE[0] - 1, GRID_SIZE[1] - 1))
    #  绘制分数
    font = pygame.font.SysFont('KaiTi', 36, bold=True)
    text_surface = font.render(f'分数：{score}', True, (255, 255, 255))
    screen.blit(text_surface, (GAME_AREA_SIZE[0], 0))


def clear_full_rows(grid):
    """清除满行并返回清除的行数"""
    rows_to_clear = []

    # 找出所有需要清除的行
    for row in range(len(grid)):
        if all(cell != 0 for cell in grid[row]):
            rows_to_clear.append(row)

    # 如果有需要清除的行
    if rows_to_clear:
        # 从上往下清除，并让上面的行下移
        for row in sorted(rows_to_clear):
            del grid[row]
            grid.insert(0, [0] * len(grid[0]))  # 插入空行在顶部

    return len(rows_to_clear)


def update_score(score, rows_cleared):
    """根据清除的行数更新得分"""
    if rows_cleared == 1:
        score += 100
    elif rows_cleared == 2:
        score += 300
    elif rows_cleared == 3:
        score += 500
    elif rows_cleared == 4:
        score += 800
    return score


def rotate_block(current_block):
    """旋转方块"""
    # 顺时针旋转矩阵
    return [list(row) for row in zip(*current_block[::-1])]


def game_over(screen, grid):
    """游戏结束"""
    for row in range(5):
        for col in range(len(grid[row])):
            if grid[row][col] != 0:
                font = pygame.font.SysFont('KaiTi', 52, bold=True)
                text_surface = font.render('Game Over', True, (255, 255, 255))
                screen.blit(text_surface,
                            (GAME_AREA_SIZE[0] // 2 - text_surface.get_width() // 2, GAME_AREA_SIZE[1] // 2))
                return True
    return False


def main():
    # 初始化
    pygame.init()
    # 加载图标（使用资源路径）
    icon_path = resource_path('icon.png')
    try:
        icon = pygame.image.load(icon_path)
        pygame.display.set_icon(icon)
    except pygame.error as e:
        print("无法加载图标:", e)
    # 设置窗口标题
    pygame.display.set_caption('俄罗斯方块')
    # 创建窗口和时钟
    screen = pygame.display.set_mode((WINDOW_SIZE[0], WINDOW_SIZE[1]))
    clock = pygame.time.Clock()

    # 定义方块和网格
    block = [
        [[1, 1, 1], [0, 1, 0]],  # T型
        [[1, 1, 1, 1]],  # I型
        [[1, 1, 1], [1, 0, 0]],  # L型
        [[1, 1, 1], [0, 0, 1]],  # J型
        [[0, 1, 1], [1, 1, 0]],  # S型
        [[1, 1, 0], [0, 1, 1]],  # Z型
        [[1, 1], [1, 1]]  # O型
    ]

    color = [
        (128, 0, 128),
        (0, 255, 255),
        (255, 165, 0),
        (0, 0, 255),
        (0, 255, 0),
        (255, 0, 0),
        (255, 255, 0)
    ]

    # 当前方块
    current_block = random.choice(block)
    current_color = random.choice(color)
    # 下一个方块
    next_block = random.choice(block)
    next_color = random.choice(color)

    block_pos = [3, 0]

    grid = [[0 for _ in range(GRID_NUM[0])] for _ in range(GRID_NUM[1])]

    # 记录得分
    score = 0

    # 设置计时器
    drop_timer = 0

    # 方块下落速度
    block_interval = 800

    # 游戏主循环
    running = True
    while running:
        # 生成一个随机方块
        if not current_block:
            current_block = next_block
            current_color = next_color
            next_block = random.choice(block)
            next_color = random.choice(color)
            block_pos = [3, 0]

        # 处理事件
        for event in pygame.event.get():
            # 处理退出事件
            if event.type == pygame.QUIT:
                running = False
            # 处理键盘事件
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_DOWN:
                    block_interval = 800
            elif event.type == pygame.KEYDOWN:
                # 左移
                if event.key == pygame.K_LEFT:
                    if block_pos[0] - 1 > 0:
                        block_pos[0] -= 1
                        if check_collision(current_block, block_pos, grid):
                            block_pos[0] += 1
                # 右移
                elif event.key == pygame.K_RIGHT:
                    if block_pos[0] - 1 < GRID_NUM[0] - len(current_block[0]):
                        block_pos[0] += 1
                        if check_collision(current_block, block_pos, grid):
                            block_pos[0] -= 1
                # 旋转
                elif event.key == pygame.K_UP:
                    new_block = rotate_block(current_block)
                    if not check_collision(new_block, block_pos, grid):
                        current_block = new_block
                # 加速下落
                elif event.key == pygame.K_DOWN:
                    block_interval = 100

        # 更新游戏状态
        current_block, block_pos, drop_timer, score = update(current_block, block_pos, current_color, block_interval,
                                                           drop_timer, grid, drop_timer, score)
        # 渲染
        screen.fill((0, 0, 0))

        # 绘制
        draw(screen, grid, current_block, current_color, block_pos, next_block, next_color, score)

        # 检查游戏结束
        if game_over(screen, grid):
            waiting = True
            while waiting:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        waiting = False
                        running = False
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_r:
                            # 重置游戏状态
                            current_block = random.choice(block)
                            current_color = random.choice(color)
                            next_block = random.choice(block)
                            next_color = random.choice(color)
                            block_pos = [3, 0]
                            grid = [[0 for _ in range(GRID_NUM[0])] for _ in range(GRID_NUM[1])]
                            score = 0
                            drop_timer = 0
                            block_interval = 800
                            waiting = False
                pygame.display.flip()

        pygame.display.flip()

        clock.tick(30)

    pygame.quit()


if __name__ == "__main__":
    main()
